﻿using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.GameAOT;
using IQIGame.Onigao.Logic;
using LFloatMath.Math;
using NetProtocol.POD;

namespace IQIGame.Onigao.GamePlay
{
    public class BattleData
    {
#if UNITY_EDITOR
        // 仅在编辑模式下使用的映射对，runtime中不可用
        public static Dictionary<EntityDriver, UnitView> editorDriver = new Dictionary<EntityDriver, UnitView>();
#endif

        public long battleId;
        public int roundNum;
        public bool autoBattle;
        public Random random;
        
        public List<UnitView> units = new List<UnitView>();
        private Dictionary<long, UnitView> unitsMap = new Dictionary<long, UnitView>();
        public Dictionary<int, BattleTeamView> teams = new Dictionary<int, BattleTeamView>();
        private Dictionary<EntityDriver, UnitView> driverUnitMap = new Dictionary<EntityDriver, UnitView>();
        private Dictionary<EntityDriver, UnitView> driverUnitTempMap = new Dictionary<EntityDriver, UnitView>();

        public void Initialize(BattleEnterPOD result)
        {
            this.battleId = result.battleId;
            this.units.Clear();
            this.unitsMap.Clear();
            this.teams.Clear();
            this.driverUnitMap.Clear();
            this.driverUnitTempMap.Clear();
            this.random = new Random((uint)result.randomSeed);
            for (int i = 0; i < result.teams.Count; i++)
            {
                this.SetTeam(result.teams[i]);
            }
        }

        private bool TryGetUnit(long guid, out UnitView unit)
        {
            if (guid <= 0)
            {
                unit = null;
                return false;
            }
            if (this.unitsMap.TryGetValue(guid, out unit))
            {
                return true;
            }
            return false;
        }
        
        public UnitView GetUnit(long uid)
        {
            if (this.TryGetUnit(uid, out var rUnit))
            {
                return rUnit;
            }
            return null;
        }

        public void SetDriverToUnit(EntityDriver driver, UnitView unit)
        {
            this.driverUnitTempMap.Clear();
            this.driverUnitTempMap.AddRange(this.driverUnitMap);
            foreach(var rPair in this.driverUnitTempMap)
            {
                if (rPair.Value == unit)
                {
                    this.driverUnitMap.Remove(rPair.Key);
                }
            }
            if (driver)
            {
                this.driverUnitMap[driver] = unit;
            }
        }

        public void RemoveDriverUnitPair(EntityDriver driver)
        {
            this.driverUnitMap.Remove(driver);
        }
        
        public bool TryGetUnitByDriver(EntityDriver driver, out UnitView unit)
        {
            if (driver)
            {
                return this.driverUnitMap.TryGetValue(driver, out unit);
            }
            unit = null;
            return false;
        }
        
        public void RemoveMonsterTeam(BattleTeamViewPOD rBattleTeam)
        {
            if (rBattleTeam.teamIndex != BattleConst.TeamBlueIndex)
            {
                return;
            }
            if (this.teams.TryGetValue(rBattleTeam.teamIndex, out var rOldTeam))
            {
                for (int i = 0; i < rOldTeam.units.Count; i++)
                {
                    this.RemoveUnit(rOldTeam.units[i]);
                }
            }
            this.teams.Remove(rBattleTeam.teamIndex);
        }
        
        public void SetTeam(BattleTeamViewPOD rBattleTeam)
        {
            this.teams[rBattleTeam.teamIndex] = new BattleTeamView().Initialize(rBattleTeam.teamIndex);
            
            for (int i = 0; i < rBattleTeam.units.Count; i++)
            {
                var rUnit = UnitViewFactory.CreateBattleUnitView(rBattleTeam.units[i], rBattleTeam.teamIndex);
                this.AddUnit(rUnit);
            }
            
        }
        
        public void AddUnit(UnitView rUnit)
        {
            this.units.Add(rUnit);
            this.unitsMap.TryAdd(rUnit.GUID, rUnit);
            this.teams[rUnit.teamIndex].units.Add(rUnit);
            MsgDispatcher.Broadcast(MsgEventType.BattleView_UnitAdd, rUnit);
        }
        
        public void RemoveUnit(UnitView rUnit)
        {
            this.teams[rUnit.teamIndex].units.Remove(rUnit);
            rUnit.Dispose();
            this.units.Remove(rUnit);
            this.unitsMap.Remove(rUnit.GUID);
            MsgDispatcher.Broadcast(MsgEventType.BattleView_UnitRemove, rUnit);
        }
        
        public List<UnitView> GetUnitByRelation(UnitView self, ETargetRelation rRelation)
        {
            List<UnitView> rAllUnits = new List<UnitView>();
            var rCurTeamIndex = self.teamIndex;
            if ((rRelation & ETargetRelation.Friend) > 0)
            {
                var rTargetIndex = BattleTeam.GetTargetTeamIndex(rCurTeamIndex, ETargetRelation.Friend);
                var rTeamUnits = this.teams[rTargetIndex].units;
                if ((rRelation & ETargetRelation.Self) > 0)
                {
                    rAllUnits.AddRange(rTeamUnits);
                }
                else
                {
                    for (int i = 0; i < rTeamUnits.Count; i++)
                    {
                        if (rTeamUnits[i] != self)
                        {
                            rAllUnits.Add(rTeamUnits[i]);
                        }
                    }
                }
            }
            else if ((rRelation & ETargetRelation.Self) > 0)
            {
                rAllUnits.Add(self);
            }

            if ((rRelation & ETargetRelation.Enemy) > 0)
            {
                var rTargetIndex = BattleTeam.GetTargetTeamIndex(rCurTeamIndex, ETargetRelation.Enemy);
                var rTeamUnits = this.teams[rTargetIndex].units;
                rAllUnits.AddRange(rTeamUnits);
            }
            
            return rAllUnits;
        }
    }
}